home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Utilities / stevie 3.10 / mac.c < prev    next >
C/C++ Source or Header  |  1991-01-03  |  14KB  |  727 lines

  1. /*
  2.  * Terminal emulator for use with Macintosh and Stevie 3.69.
  3.  * Aztec C 3.6c.
  4.  * Earle R. Horton 11/23/89.
  5.  */
  6. #include    <windows.h>
  7. #include    <events.h>
  8. #include    <menus.h>
  9. #include    <fonts.h>
  10. #include    <dialogs.h>
  11. #include    <quickdraw.h>
  12. #include    <osutils.h>
  13. #include    <desk.h>
  14. #include    <resources.h>
  15. #include    <memory.h>
  16. #include    <files.h>
  17. #include    <SegLoad.h>
  18. #undef normal
  19. #include    "stevie.h"
  20.  
  21. #define leftoffset 4
  22. #define ORIG_ROWS 24
  23. #define ORIG_COLUMNS 80
  24.  
  25. short cwd;                        /* Current working directory. */
  26. char wdname[256];         /* Working directory or volume name. */
  27. static char progname[32];         /* Program name for argv[0]. */
  28. static char pname[32];               /* Program name in Pascal. */
  29. struct Rect dragRect, pRect;
  30. struct WindowRecord wRecord;
  31. struct GrafPort *myWindow, *whichWindow;
  32. struct EventRecord myEvent;
  33. RgnHandle updateRgn;
  34. Boolean dead = false;
  35.  
  36. short x=0, y=0;
  37. static short escflg = 0, ex, ey, savex, savey;
  38.  
  39. main()
  40. {
  41.     AppFile fParm;
  42.     short    message, count, index;
  43.     Handle apparams;
  44.     short refnum;
  45.     char **Files;
  46.     extern int Rows,Columns;
  47.  
  48.     long stackframeend;
  49.  
  50.     char *lmalloc();
  51.     
  52. /* 
  53.  * Here we get the current value of the stack pointer, and set
  54.  * the end of the application heap zone to somewhat less than this.
  55.  * Then, we remove 128k of memory from the system pool and put it
  56.  * in our pool.  This helps to prevent frequent calls to malloc()
  57.  * from fragmenting the heap.  For this to work properly, please
  58.  * use an implementation where free() does NOT call DisposPtr().
  59.  *
  60.  * These numbers, with a 256k MultiFinder partition, give approximately
  61.  * the following amounts of storage:
  62.  *    25k        Stack
  63.  *    55k        System use (free and relocatable blocks)
  64.  *    128k    For use by malloc()
  65.  *    55k        CODE
  66.  */ 
  67.     SetApplLimit( (long)(&stackframeend) - 20000L );
  68.     MaxApplZone();    /* We want it. */
  69.     free(lmalloc(131072L));        /* Prime the pump. */
  70.     
  71. /*
  72.  * Are there any Files launched from the Finder?  If so, build
  73.  * a standard C program argument list.
  74.  */
  75.     CountAppFiles(&message, &count);
  76.     GetAppParms(&pname,&refnum,&apparams);
  77.     strcpy(progname,pname);
  78.     p2cstr(progname);
  79.     
  80.     Files = (char **)malloc((count+1)*sizeof(char *));
  81.     Files[0] = progname;
  82. /*
  83.  * Get default volume in case we were invoked with no files.
  84.  */
  85.     GetVol(wdname,&cwd);
  86.     /* Process the files */
  87.     for(index=1;index<=count;index++) {
  88.         GetAppFiles(index, &fParm);
  89.         ClrAppFiles(index);
  90.         Files[index]=(char *)malloc(fParm.fName.length+1);
  91.         p2cstr(&fParm.fName);
  92.         strcpy(Files[index],&fParm.fName);
  93. /*
  94.  * Use as the default directory that directory which holds the last
  95.  * file we were invoked with.  Problem if we are invoked with files
  96.  * in more than one directory and caller does not use pathnames.
  97.  */
  98.         wdname[0] = '\0';
  99.         cwd = fParm.vRefNum;
  100.     }
  101.     SetVol(wdname,cwd);
  102.     
  103.     InitGraf(&qd.thePort);
  104.     InitWindows();
  105.     InitFonts();
  106.     setupmenu();
  107.     InitDialogs(0L);
  108.     InitCursor();
  109.     
  110.     SetRect(&dragRect, 4, 24, 
  111.         qd.screenBits.bounds.right-4,
  112.             qd.screenBits.bounds.bottom-4);
  113.     
  114.     pRect.top = 40;
  115.     pRect.left = 5;
  116.     pRect.bottom = ORIG_ROWS*12;
  117.     pRect.right = (ORIG_COLUMNS+1)*6;
  118.     myWindow = NewWindow(
  119.         &wRecord,&pRect,pname,true,0,(WindowPtr)-1L,0,0L);
  120.     P(P_CO) = Columns = ORIG_COLUMNS;
  121.     P(P_LI) = Rows = ORIG_ROWS;
  122.     windresize();
  123.     SelectWindow(myWindow);
  124.     ShowWindow(myWindow);
  125.     SetPort(myWindow);
  126.     
  127.     TextFont(4);                /* monaco */
  128.     TextSize(9);
  129.     TextMode(srcCopy);
  130.     
  131.     updateRgn = NewRgn();
  132.  
  133.     xmain(count+1,Files);
  134.  
  135. }
  136. /*
  137.  * This piece of trash serves to allow our window to come up in front
  138.  * under MultiFinder.  If we have the canBackGround bit set in our
  139.  * 'SIZE' resource, then we come up in the background when MultiFinder
  140.  * is active.  Since we are an interactive application, we want to
  141.  * come up in the foreground, with user option to swap us back.  Tossing
  142.  * a few events (yuch) is the recommended way to get brought forward.
  143.  * This code also leaves any startup message on the screen for about
  144.  * a half second before we get to work.
  145.  */
  146. void windinit()
  147. {
  148.     long time;
  149.     time = TickCount() + 30L;
  150.     while(time > TickCount()){
  151.         (void)GetNextEvent(everyEvent, &myEvent);
  152.     }
  153. }
  154. /*
  155.  * Resize the window according to the globals Rows and Columns.  If window
  156.  * contents ever get buffered, this would be the time to reallocate the
  157.  * window contents buffer.
  158.  */
  159. windresize()
  160. {
  161.     SizeWindow(myWindow,(leftoffset*2)+(Columns*6),Rows*12,false);
  162. }
  163. int inchar()
  164. {
  165.     short i = 0,j = 0;
  166.     short code;
  167.     static long lastblink = 0L;
  168.     static Boolean wactive = true;
  169.     Boolean on;
  170.     long l;
  171.  
  172.     flushbuf();
  173.     SetPort(myWindow);
  174.     PenMode(patXor);
  175.     PenSize(7,11);
  176.     MoveTo(leftoffset - 1 + x * 6,y*12);
  177. /*
  178.  * Blink the cursor on.
  179.  */
  180.     if(wactive){
  181.         Line(0,0);
  182.     }
  183.     on = true;
  184.     for(; i == 0 ;){
  185.         do{
  186.             SystemTask();
  187. /*
  188.  * Blink the cursor every GetCaretTime() ticks while waiting for input.
  189.  */
  190.             if(wactive){
  191.                 if(TickCount() > (lastblink + GetCaretTime())){
  192.                     Line(0,0);
  193.                     lastblink = TickCount();
  194.                     on = !on;
  195.                 }
  196.             }
  197.         }while (!GetNextEvent(everyEvent, &myEvent));
  198. /*
  199.  * Blink the cursor off while servicing events.
  200.  */
  201.             if(wactive){
  202.                 if(on){
  203.                     Line(0,0);
  204.                     lastblink = TickCount();
  205.                     on = false;
  206.                 }
  207.             }
  208.         switch(myEvent.what) {
  209.         case mouseDown:
  210.             code = FindWindow(myEvent.where, &whichWindow);
  211.             switch (code) {
  212.             case inMenuBar:
  213.                 docommand(MenuSelect(myEvent.where));
  214.                 break;
  215.             case inSysWindow:
  216.                 SystemClick(&myEvent, whichWindow);
  217.                 break;
  218.             case inDrag:
  219.                 DragWindow(whichWindow, myEvent.where, &dragRect);
  220.                 break;
  221.             case inGrow:
  222.             case inContent:
  223.                 if (whichWindow != FrontWindow())
  224.                     SelectWindow(whichWindow);
  225.                 else {
  226.                 }
  227.                 break;
  228.             }
  229.             break;
  230. /*
  231.  * The next piece of code attempts to get a meaningful ASCII character
  232.  * out of the event record.  Some translation is done so the program
  233.  * doesn't look totally clueless with respect to basic stuff like
  234.  * arrow keys and Enter, but very little else is done except to 
  235.  * map command to control.
  236.  */
  237.         case keyDown:
  238.         case autoKey:
  239.             if (myWindow == FrontWindow()) {
  240.                 i = myEvent.message & 0xff;
  241.                 if ((myEvent.modifiers & cmdKey) && (l = MenuKey(i))) {
  242.                     docommand(l);
  243.                     i = 0;
  244.                 }
  245.                 else if (myEvent.modifiers & cmdKey) {
  246.                         if ( i == '6'){
  247.                             i = CTRL('^');
  248.                         }
  249.                         else if ( i == '/' ){    /* Actually '?'. */
  250.                             i = K_HELP;
  251.                         }else{
  252.                              i &= 0x1f;
  253.                         }
  254.                 }
  255.                 else if (State == NORMAL){
  256.                     if ( (i & 0xFF) < 0x20 ){
  257.                         switch(i){
  258.                             case CTRL('C'):
  259.                                 i = CTRL('J');
  260.                                 break;
  261.                             case CTRL('^'):
  262.                                 i = K_UARROW;
  263.                                 break;
  264.                             case CTRL('_'):
  265.                                 i = K_DARROW;
  266.                                 break;
  267.                             case CTRL(']'):
  268.                                 i = K_RARROW;
  269.                                 break;
  270.                             case CTRL('\\'):
  271.                                 i = K_LARROW;
  272.                                 break;
  273.                         }
  274.                     }
  275.                 }
  276.             }
  277.             break;
  278.  
  279.         case activateEvt:
  280. /*
  281.  * If we get an activate event, then blink the cursor on.
  282.  */
  283.             if(myEvent.message == (long)myWindow){
  284.                 if (myEvent.modifiers & activeFlag) {
  285.                     wactive = true;
  286.                 }else{
  287.                     wactive = false;
  288.                     if(on){
  289.                         Line(0,0);
  290.                         lastblink = TickCount();
  291.                         on = false;
  292.                     }
  293.                 }
  294.             }
  295.             break;
  296.  
  297.         case updateEvt:
  298.             if(myEvent.message == (long)myWindow){
  299.                 SetPort(myWindow);
  300.                 BeginUpdate(myWindow);
  301.     
  302.                 redrawit();
  303.     
  304.                 EndUpdate(myWindow);
  305.             }
  306.             break;
  307.         }
  308.     }
  309.     return i;
  310. }
  311.  
  312. /*
  313.  * Redraw the window contents.  Currently has the host program do this.
  314.  * A better alternative would be to maintain a character buffer to store
  315.  * the window contents and take care of this here.
  316.  */
  317. redrawit()
  318. {
  319.     int savex,savey;
  320.     if(!dead){
  321.         savex = x;
  322.         savey = y;
  323.         screenclear();
  324.         updatescreen();
  325.         flushbuf();
  326.         x = savex;
  327.         y = savey;
  328.         MoveTo(leftoffset - 1 + x * 6,y*12);
  329.     }
  330. }
  331. #undef exit
  332. void windexit(status)
  333. int status;
  334. {
  335.     if(status){
  336.         ParamText(pname,pname,pname,pname);
  337.         Alert(128,nil);
  338.     }
  339.     exit(status);
  340. }
  341. /*
  342.  * Substitute for [f]printf in the Mac environment.
  343.  * A more sophisticated approach might be to intercept write calls,
  344.  * but each compiler probably implements these differently.
  345.  */
  346. #undef fprintf
  347. #undef printf
  348. myfprintf(a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac)
  349. FILE *a1;
  350. char *a2;
  351. long a3,a4,a5,a6,a7,a8,a9,aa,ab,ac;
  352. {
  353.     char sbuf[2048];
  354.     char *s,c;
  355.  
  356.     if( a1 == stderr || a1 == stdout || a1 == stdin ){
  357.         sprintf(sbuf,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac);
  358.         s = &sbuf[0];
  359.         for(;(c = *s++);){
  360.             switch (c){
  361.                 case NL:
  362.                 case CR:
  363.                     outchar(0x0a);
  364.                     outchar(0x0d);
  365.                     break;
  366.                 default:
  367.                     outchar(c);
  368.                     break;
  369.             }
  370.         }
  371.         flushbuf();
  372.     }else{
  373.         fprintf(a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac);
  374.     }
  375. }
  376.  
  377. /*
  378.  * Characters are generally buffered, which means we can use StdText()
  379.  * to draw a bunch of them.  This is faster than repeated calls to
  380.  * DrawChar().
  381.  */
  382. #define    BSIZE    128
  383. static    char    outbuf[BSIZE];
  384. static    int    bpos = 0;
  385. void
  386. flushbuf()
  387. {
  388.     if (bpos != 0){
  389.         MoveTo((x*6)+leftoffset, (y*12)+9);
  390.         StdText((short)bpos,outbuf,0x00010001,0x00010001);
  391.         x += bpos;
  392.         bpos = 0;
  393.     }
  394. }
  395.  
  396. /*
  397.  * Entry point to draw characters on the screen.  Buffer them up until
  398.  * a control character appears or the buffer becomes full.
  399.  */
  400. void outchar(c)
  401. register unsigned char c;
  402. {
  403.     if(c < 0x20 || escflg != 0) {
  404.         flushbuf();
  405.         scrput(c);
  406.     }
  407.     else{
  408.         outbuf[bpos++] = c;
  409.         if (bpos >= BSIZE)
  410.             flushbuf();
  411.     }
  412. }
  413.  
  414. void outstr(s)
  415. register char *s;
  416. {
  417.     while(*s){
  418.         outchar(*s++);
  419.     }
  420. }
  421.  
  422. void beep()
  423. {
  424.     scrput('\007');
  425. }
  426.  
  427. void remove(file)
  428. char *file;
  429. {
  430.     char fsfile[256];
  431.     strcpy(fsfile,file);
  432.     c2pstr(fsfile);
  433.     FSDelete(fsfile,cwd);
  434. }
  435.  
  436. void rename(of,nf)
  437. char *of,*nf;
  438. {
  439.     char fsof[256],fsnf[256];
  440.     strcpy(fsof,of);
  441.     strcpy(fsnf,nf);
  442.     c2pstr(fsof);
  443.     c2pstr(fsnf);
  444.     SetVol(wdname,cwd);
  445.     Rename(fsof,cwd,fsnf);
  446. }
  447.  
  448. csave()
  449. {
  450.     savex = x;
  451.     savey = y;
  452. }
  453.  
  454. crestore()
  455. {
  456.     x = savex;
  457.     y = savey;
  458. }
  459.  
  460. static
  461. del_lin(lin)
  462. {
  463.     struct Rect rect;
  464.  
  465.     rect.left = 0;
  466.     rect.right = ((GrafPtr)myWindow)->portRect.right;
  467.     rect.top = lin * 12;
  468.     rect.bottom = ((GrafPtr)myWindow)->portRect.bottom;
  469.     ScrollRect(&rect, 0, -12, updateRgn);
  470. }
  471.  
  472. static
  473. ins_lin(lin)
  474. {
  475.     struct Rect rect;
  476.  
  477.     rect.left = 0;
  478.     rect.right = ((GrafPtr)myWindow)->portRect.right;
  479.     rect.top = lin * 12;
  480.     rect.bottom = ((GrafPtr)myWindow)->portRect.bottom;
  481.     ScrollRect(&rect, 0, 12, updateRgn);
  482. }
  483.  
  484. static
  485. clr_eol()
  486. {
  487.     struct Rect rect;
  488.  
  489.     rect.left = leftoffset + x * 6;
  490.     rect.top = y * 12;
  491.     rect.right = ((GrafPtr)myWindow)->portRect.right;
  492.     rect.bottom = rect.top + 13;
  493.     EraseRect(&rect);
  494. }
  495.  
  496. scrput(c)
  497. register unsigned char c;
  498. {
  499.     register short i;
  500.     struct Rect r;
  501.     GrafPtr    tmpport;
  502.     
  503.     GetPort(&tmpport);
  504.     SetPort(myWindow);
  505.  
  506.     switch(escflg) {
  507.     case 0:
  508.         switch(c) {
  509.         case 0x1b:
  510.             escflg = 1;
  511.             return;
  512.         case 0x07:
  513.             SysBeep(1);
  514.             break;
  515.         case 0x08:
  516.             if (x)
  517.                 x--;
  518.             break;
  519.         case 0x09:
  520.             c = ((x + 4) & ~3) - x;
  521.             while(c--)
  522.                 scrput(' ');
  523.             return;
  524.         case 0x0a:
  525.             if( y < (myWindow->portRect.bottom/12) - 1 )
  526.                 y++;
  527.             else del_lin(0);
  528.             break;
  529.         case 0x0d:
  530.             x = 0;
  531.             break;
  532.         default:
  533.             if (c >= 0x20){
  534.                 outbuf[bpos++] = c;
  535.                 if (bpos >= BSIZE)
  536.                     flushbuf();
  537.             }
  538.             break;
  539.         }
  540.         break;
  541.     case 1:
  542.         switch(c) {
  543.         case 'R':
  544.             del_lin(y);
  545.             x = 0;
  546.             break;
  547.         case 'E':
  548.             ins_lin(y);
  549.             x = 0;
  550.             break;
  551.         case 'T':
  552.             clr_eol();
  553.             break;
  554.         case '=':
  555.             escflg = 2;
  556.             return;
  557.         case ';':
  558.             EraseRect(&qd.thePort->portRect);
  559.             x = y = 0;
  560.             break;
  561.         case '7':
  562.             csave();
  563.             break;
  564.         case '8':
  565.             crestore();
  566.             break;
  567.         default:
  568.             break;
  569.         }
  570.         escflg = 0;
  571.         break;
  572.     case 2:
  573.         ey = c - ' ';
  574.         escflg++;
  575.         break;
  576.     case 3:
  577.         ex = c - ' ';
  578.         escflg = 0;
  579.         if (ey >= 0 && ex >= 0) {
  580.             y = ey;
  581.             x = ex;
  582.         }
  583.         break;
  584.     }
  585.  
  586.     SetPort(tmpport);
  587. }
  588.  
  589. void windgoto(r,c)
  590. register int r,c;
  591. {
  592. char cbuf[20];
  593.     sprintf(cbuf,"\033=%c%c",r + ' ',c + ' ');
  594.     outstr(cbuf);
  595. }
  596.     
  597.  
  598. #define    appleMenu    255
  599. #define    fileMenu    256
  600. #define editMenu    257
  601.  
  602. #define    NMENUS    3
  603.  
  604. MenuHandle myMenus[NMENUS];
  605.  
  606. setupmenu()
  607. {
  608.     short i;
  609.     char about[256];
  610.  
  611.     InitMenus();
  612.     myMenus[0] = GetMenu(appleMenu);
  613.     GetItem(myMenus[0],1,about);
  614.     p2cstr(about);
  615.     strcat(about,progname);
  616.     strcat(about,"…");
  617.     c2pstr(about);
  618.     SetItem(myMenus[0],1,about);
  619.     AddResMenu(myMenus[0], 'DRVR');
  620.     myMenus[1] = GetMenu(fileMenu);
  621.     myMenus[2] = GetMenu(editMenu);
  622.     for (i=0;i<NMENUS;i++)
  623.         InsertMenu(myMenus[i], 0);
  624.     DrawMenuBar();
  625. }
  626.  
  627. docommand(mResult)
  628. long mResult;
  629. {
  630.     register short i;
  631.     short theItem, theMenu;
  632.     char name[40];
  633.     int savex,savey;
  634.  
  635.     theMenu = mResult >> 16;
  636.     theItem = mResult;
  637.     switch(theMenu) {
  638.     case appleMenu:
  639.         if (theItem == 1) {
  640.             savex = x;savey = y;
  641.             help();
  642.             redrawit();
  643.             x = savex;y = savey;
  644.             MoveTo(leftoffset - 1 + x * 6,y*12);
  645.         }
  646.         else{
  647.             GetItem(myMenus[0], theItem, name);
  648.             OpenDeskAcc(name);
  649.         }
  650.         break;
  651.     case fileMenu:
  652.         windexit();
  653.         break;
  654.     case editMenu:
  655.         (void)SystemEdit(theItem - 1);
  656.         break;
  657.     }
  658.     HiliteMenu(0);
  659. }
  660.  
  661. #undef fopen
  662. FILE *
  663. fopenb(fname, mode)
  664. char    *fname;
  665. char    *mode;
  666. {
  667.     char pname[256];
  668.     FInfo info;
  669.     if ( mode[0] == 'w' ) {
  670.         strcpy(pname,fname);
  671.         c2pstr(pname);
  672.         if(GetFInfo(pname,cwd,&info) != noErr){
  673.             Create(pname,cwd,'STvi','TEXT');
  674.         }
  675.     }
  676.     SetVol(wdname,cwd);
  677.     return fopen(fname, mode);
  678. }
  679.  
  680. void
  681. doshell()
  682. {
  683. }
  684. system()
  685. {
  686. }
  687. /*
  688.  * delay() is called to flash to matching braces when showmatch is on
  689.  * in Stevie.  This version turns on the cursor, pauses for a bit, then
  690.  * turns off the cursor.
  691.  */
  692. void
  693. delay()
  694. {
  695.     long dtime = 6L;
  696.     SetPort(myWindow);
  697.     PenMode(patXor);
  698.     PenSize(7,11);
  699.     MoveTo(leftoffset - 1 + x * 6,y*12);
  700.     Line(0,0);
  701.     Delay(dtime,&dtime);
  702.     Line(0,0);
  703. }
  704. sleep()
  705. {
  706. }
  707. /*
  708.  * "Environment variables" are stored as named resources of type 'STR '.
  709.  */
  710. char *getenv(str)
  711. char str[];
  712. {
  713. char pname[256];
  714. static char result[256];
  715. char **envstr;
  716.     strcpy(pname,str);
  717.     c2pstr(pname);
  718.     if((envstr = (char **)GetNamedResource('STR ',pname)) != nil){
  719.         HLock(envstr);
  720.         p2cstr(*envstr);
  721.         strcpy(result,*envstr);
  722.         ReleaseResource(envstr);
  723.         return result;
  724.     }
  725.     else return (char *)0L;
  726. }
  727.